package de.tu_darmstadt.gdi1.xcom.view;

import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.HashMap;

import javax.swing.ImageIcon;

import de.tu_darmstadt.gdi1.framework.utils.FrameworkUtils;
import de.tu_darmstadt.gdi1.framework.utils.Point;
import de.tu_darmstadt.gdi1.xcom.controller.XcomController;
import de.tu_darmstadt.gdi1.xcom.model.elements.*;

/**
 * Maps Entities to images
 * 
 * @author michael
 *
 */
public class Tiles {
	
	private static final String FOCUS = "focus.png";
	private static final String AttackedField = "attackedField.png";
	private ImageIcon focusIcon;
	private ImageIcon attackedFieldIcon;

	private XcomController controller;

	private String path = "resource/gfx";
		
	// To add a new game element, simply add its class to this array!
	// WARNING: switch is a special case!
	private Class[] GameElems = {Monster.class,Floor.class,Human.class,Wall.class,Door.class,Medikit.class,Ammo.class};
	
	private HashMap<Class<GameElement>, HashMap<Boolean,HashMap<DirectionEnum,ImageIcon>>> mob = new HashMap<Class<GameElement>, HashMap<Boolean,HashMap<DirectionEnum,ImageIcon>>>(); // Java sucks!
	private HashMap<Class<GameElement>, HashMap<Boolean,ImageIcon>> other = new HashMap<Class<GameElement>, HashMap<Boolean,ImageIcon>>();
	private ImageIcon fallBack;
	private ImageIcon switchLocked;
	private ImageIcon switchUnlocked;
	//private ImageIcon fogOfWar;
	private ImageIcon fogWall;
	private ImageIcon fogFloor;
	
	public Tiles(XcomController controller) {
		
		this.controller = controller;
		
		fallBack		= getIconFromFile("FileNotFound.png");
		switchLocked	= getIconFromFile("SwitchLock.png");
		switchUnlocked	= getIconFromFile("SwitchOpen.png");
		//fogOfWar		= getIconFromFile("Fog.png");
		fogWall        = getIconFromFile("FogWall.png");
		fogFloor        = getIconFromFile("FogFloor.png");
		
		ImageIcon floor			= getIconFromFile("Floor.png");
		ImageIcon roofoverlay	= getIconFromFile("RoofOverlay.png");
		
		//fill HashMap with default icons
		for(Class<GameElement> gameelem : GameElems) {
			if( Mob.class.isAssignableFrom(gameelem) ) {
				String mobname = gameelem.getSimpleName();
				
				HashMap<DirectionEnum,ImageIcon> directionals = new HashMap<DirectionEnum,ImageIcon>();
				HashMap<DirectionEnum,ImageIcon> directionalsroof = new HashMap<DirectionEnum,ImageIcon>();
				for(DirectionEnum dir : DirectionEnum.values()) {
					
					ImageIcon mob = getIconFromFile(mobname+dir.toString()+".png");
					
					Image canvas = floor.getImage();
					BufferedImage composite = new BufferedImage(floor.getIconWidth(), floor.getIconHeight(), BufferedImage.TYPE_4BYTE_ABGR);
					Graphics graphics = composite.getGraphics();
					graphics.drawImage(canvas, 0, 0, null);
					graphics.drawImage(mob.getImage(), 0, 0, null);
					
					directionals.put(dir, new ImageIcon(composite));
					
					BufferedImage composite2 = new BufferedImage(floor.getIconWidth(), floor.getIconHeight(), BufferedImage.TYPE_4BYTE_ABGR);
					Graphics graphics2 = composite2.getGraphics();
					graphics2.drawImage(composite, 0, 0, null);
					graphics2.drawImage(roofoverlay.getImage(), 0, 0, null);
					directionalsroof.put(dir, new ImageIcon(composite2));
				}
				HashMap<Boolean,HashMap<DirectionEnum,ImageIcon>> hasroof = new HashMap<Boolean,HashMap<DirectionEnum,ImageIcon>>();
				hasroof.put(Boolean.TRUE, directionalsroof);
				hasroof.put(Boolean.FALSE, directionals);
				mob.put(gameelem, hasroof);
			} else {
				String thingname = gameelem.getSimpleName();
				
				HashMap<Boolean,ImageIcon> hasroof = new HashMap<Boolean,ImageIcon>();
				ImageIcon thing = getIconFromFile(thingname+".png");
				hasroof.put(Boolean.FALSE, thing);
				
				if(Wall.class.isAssignableFrom(gameelem)) {
					hasroof.put(Boolean.TRUE, getIconFromFile("Roof.png"));
				} else {
					
					BufferedImage composite = new BufferedImage(floor.getIconWidth(), floor.getIconHeight(), BufferedImage.TYPE_4BYTE_ABGR);
					Graphics graphics = composite.getGraphics();
					graphics.drawImage(thing.getImage(), 0, 0, null);
					graphics.drawImage(roofoverlay.getImage(), 0, 0, null);
					
					hasroof.put(Boolean.TRUE, new ImageIcon(composite));
				}
				other.put(gameelem, hasroof);
			}
		}
		focusIcon = getIconFromFile(FOCUS);
		attackedFieldIcon = getIconFromFile(AttackedField);
	}
	
	public ImageIcon getImageIcon(GameElement gameelem, Point pos) {
		
		// check visibility
		if(!controller.getVisibilityForField(pos)) {
			if(gameelem.isWall())
				return fogWall;
			else return fogFloor;
		}
	
	
		
		// check special cases first
		if(gameelem instanceof Switch) { 
			if(((Switch)gameelem).isLocked())
				return switchLocked;
			else return switchUnlocked;
		}
					
		
		boolean southroof = true;
		if(controller.getNeighborGameElements(pos, DirectionEnum.South)!= null)
			if(controller.getNeighborGameElements(pos, DirectionEnum.South).get(0).isWall())
				southroof = true;
			else
				southroof = false;
		
		if(gameelem instanceof Mob) {
			return mob.get(gameelem.getClass()).get(southroof).get(((Mob)gameelem).getDirection());
		}
		else {
			if(gameelem instanceof Door){
				System.out.println("There's a door!");
				if(!((Door)gameelem).isLocked()){
					return other.get(Floor.class).get(southroof);
				}
			}
			return other.get(gameelem.getClass()).get(southroof);
		}
	}
	
	private ImageIcon getIconFromFile(String filename) {
		try {
			return new ImageIcon(FrameworkUtils.loadFile(path + File.separator + filename).getPath());
		} catch (FileNotFoundException e) {
			System.err.println("Image not found: "+filename);
			return fallBack;
		}
		
	}
	
	public ImageIcon addFocus(final ImageIcon icon) {
		Image temp = icon.getImage();
		BufferedImage img = new BufferedImage(icon.getIconWidth(), icon.getIconHeight(), BufferedImage.TYPE_4BYTE_ABGR);
		Graphics graphics = img.getGraphics();
		graphics.drawImage(temp, 0, 0, null);
		graphics.drawImage(focusIcon.getImage(), 0, 0, null);
		return new ImageIcon(img);
	}
	
	public ImageIcon addAttack(final ImageIcon icon) {
		Image temp = icon.getImage();
		BufferedImage img = new BufferedImage(icon.getIconWidth(), icon.getIconHeight(), BufferedImage.TYPE_4BYTE_ABGR);
		Graphics graphics = img.getGraphics();
		graphics.drawImage(temp, 0, 0, null);
		graphics.drawImage(attackedFieldIcon.getImage(), 0, 0, null);
		return new ImageIcon(img);
	}
}
